package com.mxpio.erp.inventory.policy.impl;

import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.*;
import com.mxpio.erp.common.inventory.service.TransferOrderLineService;
import com.mxpio.erp.common.jpa.model.Order;
import com.mxpio.erp.common.order.policy.OrderContext;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.technology.entity.Item;
import com.mxpio.erp.common.technology.entity.ItemStoreProp;
import com.mxpio.erp.common.vo.OrderExcuteLineVo;
import com.mxpio.erp.inventory.policy.AbstractWoPolicy;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import com.mxpioframework.security.util.SecurityUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

public class DefaultToInWoPolicy extends AbstractWoPolicy {//调拨入仓单执行policy

	private List<OrderExcuteLineVo> orderExcuteVos;
	private TransferOrderLineService transferOrderLineService;
	public DefaultToInWoPolicy(List<OrderExcuteLineVo> orderExcuteVos, OrderLineService orderLineService) {
		this.orderExcuteVos = orderExcuteVos;
	}
	public DefaultToInWoPolicy(List<OrderExcuteLineVo> orderExcuteVos, OrderLineService orderLineService, TransferOrderLineService transferOrderLineService) {
		this.orderExcuteVos = orderExcuteVos;
		this.transferOrderLineService = transferOrderLineService;
	}
	@Override
	public void execute(OrderContext context) {
		Order order = context.getEntity();
		if(order instanceof WarehouseOrder) {
			List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();
			List<InvFlow> invFlows = new ArrayList<>();

			Map<String, BigDecimal> sumQuantity = new HashMap<String, BigDecimal>();
			String whCode = ((WarehouseOrder) order).getWhCode();//仓库编码
			String accessType = ((WarehouseOrder) order).getAccessType();
			for(OrderExcuteLineVo vo : orderExcuteVos) {
				InvFlow invFlow = new InvFlow();
				invFlow.setAccessType(accessType);
				invFlow.setItemCode(vo.getItemCode());
				invFlow.setWhCode(((WarehouseOrder) order).getWhCode());
				// 批次控制
				if(vo.getLotNo() == null) {
					context.addError("批次不能为空");
					break;
				}
				invFlow.setLotNo(vo.getLotNo());
				invFlow.setSubLotIndex(vo.getSubLotIndex());
				invFlow.setQuantity(vo.getQuantity());


				// 单据数量控制
				BigDecimal completeQuantity = context.getLotService().getMaxQuantityByWo(vo.getBizWoNo(), vo.getBizWoLineNo());
				BigDecimal currentQuan = sumQuantity.get(vo.getBizWoNo() + "#" + vo.getBizWoLineNo());
				if(currentQuan == null) {
					BigDecimal maxQuantity = vo.getLineQuantity()==null?BigDecimal.ZERO:vo.getLineQuantity();
					currentQuan = maxQuantity.subtract(completeQuantity).subtract(vo.getQuantity());
					sumQuantity.put(vo.getBizWoNo() + "#" + vo.getBizWoLineNo(),currentQuan);//处理拆批情况
				}else {
					currentQuan = currentQuan.subtract(vo.getQuantity());
				}
				if(currentQuan.compareTo(BigDecimal.ZERO) < 0) {
					context.addError("物料：" + invFlow.getItemCode() + "超过最大执行数量");
					break;
				}

				invFlow.setMemo(((WarehouseOrder) order).getMemo());
				invFlow.setOriginBizNo(((WarehouseOrder) order).getOriginBizNo());
				invFlow.setOriginBizType(((WarehouseOrder) order).getOriginBizType());
				invFlow.setOriginBizLineNo(vo.getBizOrderlineNo());
				invFlow.setWoBizNo(((WarehouseOrder) order).getBizNo());
				invFlow.setWoBizType(((WarehouseOrder) order).getWoType());
				invFlow.setWoBizLineNo(vo.getBizWoLineNo());
				invFlows.add(invFlow);
			}
			if(CollectionUtils.isEmpty(context.getErrors())) {
				JpaUtil.save(invFlows);
			}
		}else {
			context.addError("单据类型错误");
		}
	}

	@Override
	public OrderContext config(OrderContext context) {
		context.setOrderExcuteVos(orderExcuteVos);
		return context;
	}

	@Override
	public boolean beforeExecute(OrderContext context) {
		return true;
	}

	@Override
	public void afterExecute(OrderContext context) {
		if(CollectionUtils.isEmpty(context.getErrors())){
			Order wo = context.getEntity();
			if (judgeWOCompletion(context)){
				if(StringUtils.isBlank(wo.getExecutor())) {
					wo.setExecuteTime(new Date());
					wo.setExecutor(SecurityUtils.getLoginUsername());
				}
				wo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
				JpaUtil.update(wo);
				if (transferOrderLineService != null) {
					String originBizNo = ((WarehouseOrder) wo).getOriginBizNo();
					Criteria c = Criteria.create().addCriterion("bizNo", Operator.EQ, originBizNo);
					List<TransferOrderLine> transferOrderLines = transferOrderLineService.list(TransferOrderLine.class, c);
					transferOrderLineService.handleBillQuantity(originBizNo, transferOrderLines);
					for (TransferOrderLine transferOrderLine : transferOrderLines) {
						BigDecimal last = transferOrderLine.getQuantity().subtract(transferOrderLine.getPlanOutQuantity()).subtract(transferOrderLine.getActualOutQuantity());
						if (last.compareTo(BigDecimal.ZERO) != 0) {
							return;
						}
					}
					//更新调拨单主单执行状态
					JpaUtil.linu(TransferOrder.class).equal("bizNo",originBizNo).set("orderStatus",OrderStatusEnums.OrderStatus.FINISHED.getStatusCode()).update();
				}
			}else{
				if(OrderStatusEnums.OrderStatus.ORDERED.getStatusCode().equals(wo.getOrderStatus())||
						OrderStatusEnums.OrderStatus.PLAN.getStatusCode().equals(wo.getOrderStatus())) {
					wo.setOrderStatus(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode());
					wo.setExecuteTime(new Date());
					wo.setExecutor(SecurityUtils.getLoginUsername());
					JpaUtil.update(wo);
				}
			}
		}
	}

	private boolean judgeWOCompletion(OrderContext context){//判断仓单是否已执行完毕
		Order order = context.getEntity();
		List<WarehouseOrderLine> lines = JpaUtil.linq(WarehouseOrderLine.class).equal("bizNo", order.getBizNo()).list();
		if (lines.size()>0){
			String accessType = ((WarehouseOrder) order).getAccessType();
			if(OrderEnums.AccessType.OUT.getCode().equals(accessType)) {
				Set<String> itemCodeSet = lines.stream().map(WarehouseOrderLine::getItemCode).collect(Collectors.toSet());
				List<ItemStoreProp> itemStorePropList = JpaUtil.linq(ItemStoreProp.class).equal("propType", "item").in("code", itemCodeSet).list();
				if (itemStorePropList.size()>0){
					List<Item> itemList = JpaUtil.linq(Item.class).in("itemCode", itemCodeSet).list();
					Map<String, Item> itemMap = JpaUtil.index(itemList, "itemCode");
					Map<String, ItemStoreProp> itemStorePropMap = JpaUtil.index(itemStorePropList, "code");
					for (WarehouseOrderLine line:lines){
						String itemCode = line.getItemCode();
						if (itemStorePropMap.containsKey(itemCode)){
							ItemStoreProp itemStoreProp = itemStorePropMap.get(itemCode);
							Item item = itemMap.get(itemCode);
							if (itemStoreProp!=null&&itemStoreProp.getToleranceRange()!=null&&itemStoreProp.getToleranceRange().compareTo(BigDecimal.ZERO)>0){
								BigDecimal toleranceRange = itemStoreProp.getToleranceRange().divide(new BigDecimal("100"));//转化成小数
								Integer scale = item.getScale();//精度
								BigDecimal lineQuantity = line.getQuantity();
								BigDecimal toleranceRangeQuantity = lineQuantity.multiply(toleranceRange);
								line.setToleranceRangeQuantity(toleranceRangeQuantity.setScale(scale, RoundingMode.CEILING));
							}
						}
						if (line.getToleranceRangeQuantity()==null){//为空就指定为0
							line.setToleranceRangeQuantity(BigDecimal.ZERO);
						}
					}
				}
				for (WarehouseOrderLine line:lines){
					BigDecimal completeQuantity = context.getLotService().getMaxQuantityByWo(line.getBizNo(), line.getLineNo());
					if (line.getQuantity().subtract(line.getToleranceRangeQuantity()).compareTo(completeQuantity)>0){
						return false;
					}
				}
			}else{//入库操作还按之前的校验逻辑
				for (WarehouseOrderLine line:lines){
					BigDecimal completeQuantity = context.getLotService().getMaxQuantityByWo(line.getBizNo(), line.getLineNo());
					if (line.getQuantity().compareTo(completeQuantity)!=0){
						return false;
					}
				}
			}
		}else{
			return false;
		}
		return true;
	}
}
